// HWInfo.cpp : Defines the entry point for the console application.
//

#include "HWInfo.h"



void InitCL(vector<DEVICE_INFO> *dev)
{
	 
	 DEVICE_INFO d;
	 
	 // Dynamic linkiiiing
    if((hDll = LoadLibrary(L"OpenCL.dll")) == NULL)
		throw (string("Error in loading OpenCL.dll"));


	
	//We will use all this function
	pClGetPlatformIDs = (CLGETPLATFORMIDS)GetProcAddress(hDll,"clGetPlatformIDs");
	pClGetPlatformInfo = (CLGETPLATFORMINFO)GetProcAddress(hDll,"clGetPlatformInfo");
	pClGetDeviceInfo = (CLGETDEVICEINFO)GetProcAddress(hDll,"clGetDeviceInfo");
	pClGetDeviceIDs = (CLGETDEVICEIDS)GetProcAddress(hDll,"clGetDeviceIDs");
	

	//Check if they were found in dll and successfully load.
	if(pClGetPlatformIDs == NULL || pClGetPlatformInfo == NULL ||
	    pClGetDeviceInfo == NULL || pClGetDeviceIDs == NULL)
		throw (string("Error in loading functions"));

	//Get platform count
	pClGetPlatformIDs(0,NULL,&numPlatforms);

	if(!(numPlatforms > 0))
		throw (string("Error in getting platform count"));

	platforms = new cl_platform_id[numPlatforms];
	
	//Get platform ids
	status = pClGetPlatformIDs(numPlatforms,platforms, NULL);
	if(status != CL_SUCCESS)
		throw (string("Error: Getting platform IDs. (clgetPlatformsID)s"));

	//Get some info about each platform
	for(unsigned int i = 0;i<numPlatforms;i++)
	{
		char pbuff[100];
		status = pClGetPlatformInfo(
					platforms[i],
					CL_PLATFORM_VENDOR,
					sizeof(pbuff),
					pbuff,
					NULL);
		if(status != CL_SUCCESS)
			throw (string("Error: Getting Platforms Info. (clGetPlatformInfo)"));

		
		status = pClGetDeviceIDs(platforms[i],CL_DEVICE_TYPE_ALL,0,NULL,&numDevices);
		if(status != CL_SUCCESS)
			throw (string("Error: Getting Devices num . (clGetDeviceIDs)"));
			
		devices = new cl_device_id[numDevices];
		
		status = pClGetDeviceIDs(platforms[i],CL_DEVICE_TYPE_ALL,numDevices,devices,NULL);
		if(status != CL_SUCCESS)
			throw (string("Error: Getting Devices . (clGetDeviceIDs)"));
		
		
		//Get some info about each device
		for(unsigned int j = 0;j < numDevices;++j)
		{
			char dbuff[1024];
			cl_uint ret;
			size_t rett;
			size_t rety[3];
			cl_ulong retl;
			cl_bool retb;
			
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_TYPE,
					sizeof(d.cl_device_type),
					&d.cl_device_type,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
		
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_NAME,
					sizeof(d.cl_device_name),
					&d.cl_device_name,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
								
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_VENDOR,
					sizeof(d.cl_device_vendor),
					&d.cl_device_vendor,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
		
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_VENDOR_ID,
					sizeof(d.cl_device_vendor_id),
					&d.cl_device_vendor_id,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
					
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_MAX_COMPUTE_UNITS,
					sizeof(d.cl_device_max_compute_units),
					&d.cl_device_max_compute_units,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
		
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS,
					sizeof(d.cl_device_max_work_item_dimensions),
					&d.cl_device_max_work_item_dimensions,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
		
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_MAX_WORK_ITEM_SIZES,
					sizeof(d.cl_device_max_work_item_sizes),
					&d.cl_device_max_work_item_sizes,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
		
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_MAX_WORK_GROUP_SIZE,
					sizeof(d.cl_device_max_work_group_size),
					&d.cl_device_max_work_group_size,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
		
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR,
					sizeof(d.cl_device_preferred_vector_width_char),
					&d.cl_device_preferred_vector_width_char,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
		
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT,
					sizeof(d.cl_device_preferred_vector_width_short),
					&d.cl_device_preferred_vector_width_short,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
		
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT,
					sizeof(d.cl_device_preferred_vector_width_int),
					&d.cl_device_preferred_vector_width_int,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
		
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG,
					sizeof(d.cl_device_preferred_vector_width_long),
					&d.cl_device_preferred_vector_width_long,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
		
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT,
					sizeof(d.cl_device_preferred_vector_width_float),
					&d.cl_device_preferred_vector_width_float,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
		
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE,
					sizeof(d.cl_device_preferred_vector_width_double),
					&d.cl_device_preferred_vector_width_double,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
		
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_MAX_CLOCK_FREQUENCY,
					sizeof(d.cl_device_max_clock_frequency),
					&d.cl_device_max_clock_frequency,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
		
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_ADDRESS_BITS,
					sizeof(d.cl_device_address_bits),
					&d.cl_device_address_bits,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
		
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_MAX_MEM_ALLOC_SIZE,
					sizeof(d.cl_device_max_mem_alloc_size),
					&d.cl_device_max_mem_alloc_size,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
		
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_IMAGE_SUPPORT,
					sizeof(d.cl_device_image_support),
					&d.cl_device_image_support,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
		
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_MAX_READ_IMAGE_ARGS,
					sizeof(d.cl_device_max_read_image_args),
					&d.cl_device_max_read_image_args,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
			
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_MAX_WRITE_IMAGE_ARGS,
					sizeof(d.cl_device_max_write_image_args),
					&d.cl_device_max_write_image_args,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
			
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_IMAGE2D_MAX_WIDTH,
					sizeof(d.cl_device_image2d_max_width),
					&d.cl_device_image2d_max_width,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
				
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_IMAGE2D_MAX_HEIGHT,
					sizeof(d.cl_device_image2d_max_height),
					&d.cl_device_image2d_max_height,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
				
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_IMAGE3D_MAX_WIDTH,
					sizeof(d.cl_device_image3d_max_width),
					&d.cl_device_image3d_max_width,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
				
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_IMAGE3D_MAX_HEIGHT,
					sizeof(d.cl_device_image3d_max_height),
					&d.cl_device_image3d_max_height,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
				
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_IMAGE3D_MAX_DEPTH,
					sizeof(d.cl_device_image3d_max_depth),
					&d.cl_device_image3d_max_depth,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
				
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_MAX_SAMPLERS,
					sizeof(d.cl_device_max_samplers),
					&d.cl_device_max_samplers,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
				
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_MAX_PARAMETER_SIZE,
					sizeof(d.cl_device_max_parameter_size),
					&d.cl_device_max_parameter_size,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
				
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_MEM_BASE_ADDR_ALIGN,
					sizeof(d.cl_device_mem_base_addr_align),
					&d.cl_device_mem_base_addr_align,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
				
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE,
					sizeof(d.cl_device_min_data_type_align_size),
					&d.cl_device_min_data_type_align_size,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
				
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_SINGLE_FP_CONFIG,
					sizeof(d.cl_device_single_fp_config),
					&d.cl_device_single_fp_config,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
				
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_GLOBAL_MEM_CACHE_TYPE,
					sizeof(d.cl_device_global_mem_cache_type),
					&d.cl_device_global_mem_cache_type,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
		
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_GLOBAL_MEM_CACHE_SIZE,
					sizeof(d.cl_device_global_mem_cache_size),
					&d.cl_device_global_mem_cache_size,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
		
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_GLOBAL_MEM_SIZE,
					sizeof(d.cl_device_global_mem_size),
					&d.cl_device_global_mem_size,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
		
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE,
					sizeof(d.cl_device_max_constant_buffer_size),
					&d.cl_device_max_constant_buffer_size,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
			
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_MAX_CONSTANT_ARGS,
					sizeof(d.cl_device_max_constant_args),
					&d.cl_device_max_constant_args,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
				
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_LOCAL_MEM_SIZE,
					sizeof(d.cl_device_local_mem_size),
					&d.cl_device_local_mem_size,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
		
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_LOCAL_MEM_TYPE,
					sizeof(d.cl_device_local_mem_type),
					&d.cl_device_local_mem_type,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
		
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_ERROR_CORRECTION_SUPPORT,
					sizeof(d.cl_device_error_correction_support),
					&d.cl_device_error_correction_support,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
				
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_PROFILING_TIMER_RESOLUTION,
					sizeof(d.cl_device_profiling_timer_resolution),
					&d.cl_device_profiling_timer_resolution,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
				
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_ENDIAN_LITTLE,
					sizeof(d.cl_device_endian_little),
					&d.cl_device_endian_little,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
			
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_AVAILABLE,
					sizeof(d.cl_device_available),
					&d.cl_device_available,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
				
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_COMPILER_AVAILABLE,
					sizeof(d.cl_device_compiler_available),
					&d.cl_device_compiler_available,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
				
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_EXECUTION_CAPABILITIES,
					sizeof(d.cl_device_execution_capabilities),
					&d.cl_device_execution_capabilities,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
				
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_QUEUE_PROPERTIES,
					sizeof(d.cl_device_queue_properties),
					&d.cl_device_queue_properties,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
			
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_PLATFORM,
					sizeof(d.cl_device_platform),
					&d.cl_device_platform,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
	
			status = pClGetDeviceInfo(
					devices[j],
					CL_DRIVER_VERSION,
					sizeof(d.cl_driver_version),
					&d.cl_driver_version,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
		
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_VERSION,
					sizeof(d.cl_device_version),
					&d.cl_device_version,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
		
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_PROFILE,
					sizeof(d.cl_device_profile),
					&d.cl_device_profile,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
		
			status = pClGetDeviceInfo(
					devices[j],
					CL_DEVICE_EXTENSIONS,
					sizeof(d.cl_device_extensions),
					&d.cl_device_extensions,
					NULL);
			if(status != CL_SUCCESS)
				throw (string("Error: Getting Platforms Info. (pClGetDeviceInfo)"));
		
			(*dev).push_back(d);
		}
		
	
		}

	
}	


DWORD getGAInfoFromReg(vector<GRAPHIC_ADAPTER> *graphicsAdapters)
{
	HKEY hKey = 0;
	HKEY tmpKey = 0;
	DWORD dwType = 0;
	DWORD dwBufSize = sizeof(char)*MAX_KEY_LENGTH;
	DWORD status;
	
	
		
	LPCWSTR subkey = TEXT("SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E968-E325-11CE-BFC1-08002BE10318}");
	
	
	
	if((status =  RegOpenKeyEx(HKEY_LOCAL_MACHINE,subkey,0,KEY_READ ,&hKey)) != ERROR_SUCCESS)
	{	
		cout<<"Unknown error" << endl;
		return status;
	}
	
	for(int i = 0;;i++)
	{
		TCHAR     lpName[MAX_KEY_LENGTH];
		DWORD     lpcName = MAX_KEY_LENGTH;
		
		status = RegEnumKeyEx(hKey,i,lpName,&lpcName,0,NULL,NULL,NULL);		
		if(status == ERROR_NO_MORE_ITEMS)
		{
			break;
		}
		
		tmpKey = hKey;
		if( RegOpenKeyEx(hKey,lpName,0,KEY_READ ,&hKey) != ERROR_SUCCESS)
		{
			hKey = tmpKey;
			continue;
		}
		
		GRAPHIC_ADAPTER ga;
		
		 
		dwType = REG_SZ;
		BYTE buf[MAX_KEY_LENGTH] = {5};
		dwBufSize = MAX_KEY_LENGTH;
		if( RegQueryValueEx(hKey,L"DriverDesc",0, &dwType, buf, &dwBufSize) != ERROR_SUCCESS)
		{
			continue;
		}
		for(unsigned int j = 0;j<dwBufSize;j++)
		{
			if(buf[j] == 0) continue;
			ga.name += (buf[j]);
		}
				
		char buf1[MAX_KEY_LENGTH] = {0};
		dwBufSize = MAX_KEY_LENGTH;
		if( RegQueryValueEx(hKey,L"DriverVersion",0, &dwType, (BYTE*)buf1, &dwBufSize) != ERROR_SUCCESS)
		{
			continue;
		}
		for(unsigned int j = 0;j<dwBufSize;j++)
		{
			if(buf1[j] == 0) continue;
			ga.driverVersion += (buf1[j]);
		}
		
		(*graphicsAdapters).push_back(ga);
				
		hKey = tmpKey;
	}

	
	
	return 0;
}

int main(int argc, char* argv[])
{
	
	DWORD ret;
	
	vector<DEVICE_INFO> dev;
	
	vector<GRAPHIC_ADAPTER> graphicsAdapters;
		
	if((ret = getGAInfoFromReg(&graphicsAdapters)) != ERROR_SUCCESS)
	{
		cout<< "error: (" << status << ")" << endl; 
	}
	
	cout << "Num Graphic devices: " <<graphicsAdapters.size() << endl;
	
	
	try
	{
		InitCL(&dev);
		cout << "Num OpenCL devices: " <<dev.size() << endl;
	}
	catch(string s) 
	{
		cout << s << endl;
	}
	
	}
